package jmine.tec.services.environment;

import java.net.URL;
import java.sql.SQLException;
import java.util.List;

import jmine.tec.environment.db.DBEnvironment;
import jmine.tec.environment.db.DBEnvironmentHolder;
import jmine.tec.environment.db.DBLoadedServerUtils;
import jmine.tec.environment.db.PostscriptEntryLoader;
import jmine.tec.executionlog.dao.ExecutionLogDAO;
import jmine.tec.executionlog.dao.ExecutionLogItemDAO;
import jmine.tec.executionlog.domain.ExecutionLog;
import jmine.tec.executionlog.domain.ExecutionLogItem;
import jmine.tec.executionlog.domain.enumx.ExecutionStatus;
import jmine.tec.services.ServicesController;

import org.apache.log4j.Logger;
import org.springframework.transaction.TransactionStatus;

import bancosys.tec.datadigester.DataDigesterController;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.dataset.HibernateRandomAccessResultSet;
import bancosys.tec.utils.db.descriptor.ReferenceDatabaseEntry;

/**
 * Entry loader that delegates to the DataDigesterController
 * 
 * @author lundberg
 */
public abstract class AbstractRefdbPostscriptEntryLoader implements PostscriptEntryLoader {

    private static final Logger LOGGER = Logger.getLogger(AbstractRefdbPostscriptEntryLoader.class);

    /**
     * {@inheritDoc}
     */
    public boolean load(DBEnvironment environment, ReferenceDatabaseEntry entry) {
        if (matches(entry)) {
            execute(environment, entry);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Checks if this loader should handle the entry
     * 
     * @param entry entry
     * @return boolean
     */
    protected abstract boolean matches(ReferenceDatabaseEntry entry);

    /**
     * Processes the entry
     * 
     * @param environment environment
     * @param entry entry
     */
    public void execute(DBEnvironment environment, ReferenceDatabaseEntry entry) {
        URL url = this.getClass().getClassLoader().getResource(entry.getClasspathResourcePath());
        if (url == null) {
            throw new RuntimeException("File " + entry.getClasspathResourcePath() + " could not be loaded.");
        }
        try {
            environment.getHelper().closeConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        TransactionStatus ts = getHelper(environment).getTransactionStatus();
        try {
            doLoad(environment, entry, url);
        } catch (Exception t) {
            LOGGER.error(t.getMessage(), t);
            throw new RuntimeException(showErrors(environment));
        } finally {
            getHelper(environment).commit(ts);
        }
    }

    /**
     * Loads the given file
     * 
     * @param environment environment
     * @param entry entry
     * @param url url
     * @throws Exception Exception
     */
    protected abstract void doLoad(DBEnvironment environment, ReferenceDatabaseEntry entry, URL url) throws Exception;

    /**
     * Retorna os erros registrados no execution log.
     * 
     * @return erros do execution log.
     */
    private String showErrors(DBEnvironment environment) {
        ExecutionLogDAO logDao = getDAOFactory(environment).getDAOByClass(ExecutionLogDAO.class);
        List<ExecutionLog> logs = logDao.findAll();
        StringBuilder sb = new StringBuilder();
        ExecutionLogItemDAO logItemDAO = getDAOFactory(environment).getDAOByClass(ExecutionLogItemDAO.class);

        for (ExecutionLog executionLog : logs) {
            if (executionLog.getStatus().equals(ExecutionStatus.NOT_OK)) {
                HibernateRandomAccessResultSet<ExecutionLogItem> set = logItemDAO.findByExecutionLog(executionLog, null);
                for (ExecutionLogItem item : set) {
                    sb.append("Error executing service: \n");
                    sb.append(item.getContent());
                    sb.append("\n");
                    sb.append(item.getStackTrace());
                    sb.append("\n");
                    sb.append(item.getMessage());
                }
            }
        }
        return sb.toString();
    }

    /**
     * @param environment environment
     * @return DataDigesterController
     */
    protected DataDigesterController getDataDigesterController(DBEnvironment environment) {
        return (DataDigesterController) getHelper(environment).getBeanFactory().getBean("dataDigesterController");
    }

    /**
     * @param environment environment
     * @return ServicesController
     */
    protected ServicesController getServicesController(DBEnvironment environment) {
        return (ServicesController) getHelper(environment).getBeanFactory().getBean("servicesController");
    }

    /**
     * @param environment environment
     * @return BaseDAOFactory
     */
    protected BaseDAOFactory getDAOFactory(DBEnvironment environment) {
        return (BaseDAOFactory) getHelper(environment).getBeanFactory().getBean("daoFactory");
    }

    /**
     * @param environment environment
     * @return DBEnvironmentHolder
     */
    protected DBLoadedServerUtils getHelper(DBEnvironment environment) {
        return DBEnvironmentHolder.getInstance().getEnvironment().getHelper();
    }

}
